// function.js
import { query, add, update, remove, getDocById, count, db } from '@/api/appwx';
import { functionDefinitions } from './functionDefinitions';

/**
 * 函数调用工具集合
 * 用于与AI模型交互时提供数据库操作能力
 * 
 * 重要提示：
 * 1. 所有查询函数都实现了容错机制，当主要查询方式失败时会尝试多种备选方案
 * 2. 对于模糊查询，会尝试多种关键词组合以提高查询成功率
 * 3. 所有函数都返回统一格式的结果：{ status: 'success'|'error', data?: any, message: string }
 * 4. 时间段的格式必须严格遵循：1-4的数字数组，表示不同的时间段
 * 
 * 错误处理策略：
 * 1. 查询失败时会自动尝试其他查询方式
 * 2. 参数格式错误时会尝试自动修复
 * 3. 所有错误都会被捕获并返回友好的错误信息
 */

/**
 * 模型处理预约的流程指南:
 * 1. 当用户表达预约意图时，应该首先调用reservationProcess函数进行一站式预约处理
 * 2. 如果用户提供的信息不完整，应该:
 *    a. 首先调用getUserInfo获取用户信息
 *    b. 如需要，调用getTodayDate获取当前日期
 *    c. 如用户未指定实验室，调用queryLabs让用户选择
 *    d. 如用户已选实验室但未指定设备，调用queryEquipment让用户选择设备
 *    e. 确认用户选择的时间段
 *    f. 最终必须调用addReservation完成预约记录的添加
 * 3. 预约完成后，可调用queryReservations查询用户的预约记录并展示给用户
 * 
 * 重要：实验室和设备是两个完全不同的概念：
 * - 实验室(Lab)是物理空间，包含多个设备，通过queryLabs函数查询
 * - 设备(Equipment)是实验室内的具体仪器设备，通过queryEquipment函数查询
 * - 查询设备时可以提供实验室ID(sysId)作为参数进行过滤，也可以不提供sysId查询所有设备
 * - 如果用户询问设备，请直接使用queryEquipment函数，不要混淆使用queryLabs
 * - 如果一次查询失败，请尝试其他查询方法，确保能找到用户需要的信息
 * 
 * 查询容错策略：
 * 1. 实验室查询：
 *    - 先尝试完整名称查询
 *    - 如果失败，尝试关键词拆分查询（如"计算机实验室"拆分为"计算机"）
 *    - 如果还是失败，尝试模糊匹配
 * 2. 设备查询：
 *    - 先尝试完整名称查询
 *    - 如果失败，尝试关键词查询
 *    - 如果还是失败，尝试模糊匹配
 * 
 * 注意: 在任何情况下，无论流程如何，在用户表达预约意图并提供足够信息后，
 * 都必须确保最终执行到addReservation步骤，完成预约记录的添加。
 */

const functions = {
  /**
   * 获取今日日期
   * @returns {Object} 包含今日日期的对象，格式为YYYY-MM-DD
   * @throws {Error} 如果日期获取失败
   */
  getTodayDate() {
    console.log('调用getTodayDate函数');

    try {
      const today = new Date();
      const year = today.getFullYear();
      const month = String(today.getMonth() + 1).padStart(2, '0');
      const day = String(today.getDate()).padStart(2, '0');

      const formattedDate = `${year}-${month}-${day}`;

      return {
        status: 'success',
        data: formattedDate,
        message: `今日日期：${formattedDate}`
      };
    } catch (error) {
      console.error('获取今日日期失败:', error);
      return {
        status: 'error',
        message: `获取今日日期失败: ${error.message}`
      };
    }
  },

  /**
   * 查询实验室列表
   * 实现了多重容错机制：
   * 1. 先尝试完整名称查询
   * 2. 如果失败，尝试关键词拆分查询
   * 3. 如果还是失败，尝试模糊匹配
   * 
   * @param {Object} params 查询参数
   * @param {string} [params.searchValue=''] 搜索关键词
   * @param {number} [params.offset=0] 分页起始位置
   * @param {number} [params.pageSize=10] 每页数量
   * @returns {Promise<Object>} 查询结果
   */
  async queryLabs({ searchValue = '', offset = 0, pageSize = 10 }) {
    console.log('调用queryLabs函数:', { searchValue, offset, pageSize });

    try {
      let condition = {};

      // 默认查询：无论是否有搜索值，都先执行一次基础查询
      let result = await query('syslb', condition, { skip: offset, limit: pageSize });

      // 策略1：如果有搜索值，执行完整名称查询
      if (searchValue) {
        condition.name = new RegExp(searchValue, 'i');
        result = await query('syslb', condition, { skip: offset, limit: pageSize });
      }

      // 策略2：如果完整查询结果为空，尝试关键词拆分查询
      if (!result?.data?.length && searchValue) {
        const keywords = searchValue.split(/[\s,，]+/);
        condition = {
          $or: keywords.map(keyword => ({ name: new RegExp(keyword, 'i') }))
        };
        result = await query('syslb', condition, { skip: offset, limit: pageSize });
      }

      // 策略3：如果还是失败，尝试模糊匹配
      if (!result?.data?.length && searchValue) {
        condition = {
          $or: [
            { name: new RegExp(searchValue, 'i') },
            { description: new RegExp(searchValue, 'i') },
            { location: new RegExp(searchValue, 'i') }
          ]
        };
        result = await query('syslb', condition, { skip: offset, limit: pageSize });
      }

      return {
        status: 'success',
        data: result.data || [],
        message: `成功查询到${result.data ? result.data.length : 0}个实验室`
      };
    } catch (error) {
      console.error('查询实验室列表失败:', error);
      return {
        status: 'error',
        message: `查询实验室列表失败: ${error.message}`
      };
    }
  },

  /**
   * 查询设备列表
   * 实现了多重容错机制：
   * 1. 先尝试完整名称查询
   * 2. 如果失败，尝试关键词查询
   * 3. 如果还是失败，尝试模糊匹配
   * 
   * @param {Object} params 查询参数
   * @param {string} [params.sysId] 实验室ID（可选）
   * @returns {Promise<Object>} 查询结果
   */
  async queryEquipment({ sysId }) {
    console.log('调用queryEquipment函数:', { sysId });

    try {
      let condition = {};
      let result;

      // 如果提供了sysId，按特定实验室筛选设备
      if (sysId) {
        condition.sysID = sysId;
      }

      // 策略1：完整名称查询
      result = await query('sblb', condition);

      // 策略2：如果查询失败，尝试模糊匹配
      if (!result?.data?.length) {
        condition = {
          ...condition,
          $or: [
            { name: new RegExp(sysId, 'i') },
            { description: new RegExp(sysId, 'i') },
            { type: new RegExp(sysId, 'i') }
          ]
        };
        result = await query('sblb', condition);
      }

      return {
        status: 'success',
        data: result.data || [],
        message: `成功查询到${result.data ? result.data.length : 0}个设备`
      };
    } catch (error) {
      console.error('查询设备列表失败:', error);
      return {
        status: 'error',
        message: `查询设备列表失败: ${error.message}`
      };
    }
  },

  /**
   * 查询预约记录
   * 实现了多重容错机制：
   * 1. 先尝试精确匹配
   * 2. 如果失败，尝试模糊匹配
   * 3. 如果还是失败，尝试关键词拆分查询
   * 
   * @param {Object} params 查询参数
   * @param {string} params.personId 用户ID
   * @param {string} [params.sysName=''] 实验室名称
   * @param {number} [params.offset=0] 分页起始位置
   * @param {number} [params.pageSize=10] 每页数量
   * @returns {Promise<Object>} 查询结果
   */
  async queryReservations({ personId, sysName = '', offset = 0, pageSize = 10 }) {
    console.log('调用queryReservations函数:', { personId, sysName, offset, pageSize });

    try {
      let condition = {};
      let result;

      // 构建基础查询条件
      if (personId) {
        condition.personID = personId;
      }

      // 策略1：精确匹配实验室名称
      if (sysName) {
        condition.sysName = sysName;
        result = await query('yyjl', condition, { skip: offset, limit: pageSize });
      }

      // 策略2：如果精确匹配失败，尝试模糊匹配
      if (!result?.data?.length && sysName) {
        condition.sysName = new RegExp(sysName, 'i');
        result = await query('yyjl', condition, { skip: offset, limit: pageSize });
      }

      // 策略3：如果还是失败，尝试关键词拆分查询
      if (!result?.data?.length && sysName) {
        const keywords = sysName.split(/[\s,，]+/);
        condition = {
          ...condition,
          $or: keywords.map(keyword => ({ sysName: new RegExp(keyword, 'i') }))
        };
        result = await query('yyjl', condition, { skip: offset, limit: pageSize });
      }

      // 如果所有策略都失败，返回空结果
      if (!result?.data?.length) {
        return {
          status: 'success',
          data: [],
          message: '未找到匹配的预约记录'
        };
      }

      return {
        status: 'success',
        data: result.data || [],
        message: `成功查询到${result.data ? result.data.length : 0}条预约记录`
      };
    } catch (error) {
      console.error('查询预约记录失败:', error);
      return {
        status: 'error',
        message: `查询预约记录失败: ${error.message}`
      };
    }
  },

  /**
   * 检查时间段是否冲突
   * @param {string} date 日期
   * @param {Array<number>} timeSlots 时间段
   * @param {string} excludeId 要排除的预约ID（用于编辑时）
   * @returns {Promise<Object>} 检查结果
   */
  async checkTimeConflict(date, timeSlots, excludeId = null) {
    console.log('调用checkTimeConflict函数:', { date, timeSlots, excludeId });

    try {
      // 构建查询条件
      const condition = {
        date: date,
        stauts: '已预约'
      };

      // 如果有要排除的ID，添加到条件中
      if (excludeId) {
        condition._id = { $ne: excludeId };
      }

      // 查询该日期的所有预约记录
      const result = await query('yyjl', condition);

      if (!result?.data?.length) {
        return {
          status: 'success',
          hasConflict: false,
          message: '时间段可用'
        };
      }

      // 检查时间段是否冲突
      const hasConflict = result.data.some(reservation => {
        const existingSlots = reservation.time;
        return timeSlots.some(slot => existingSlots.includes(slot));
      });

      return {
        status: 'success',
        hasConflict,
        message: hasConflict ? '时间段已被预约' : '时间段可用'
      };
    } catch (error) {
      console.error('检查时间段冲突失败:', error);
      return {
        status: 'error',
        message: `检查时间段冲突失败: ${error.message}`
      };
    }
  },

  /**
   * 检查当前时间是否在预约时间段内
   * @param {string} date 日期
   * @param {Array<number>} timeSlots 时间段
   * @returns {Object} 检查结果
   */
  checkCurrentTimeInSlots(date, timeSlots) {
    console.log('调用checkCurrentTimeInSlots函数:', { date, timeSlots });

    try {
      const today = new Date();
      const currentDate = today.toISOString().split('T')[0];
      const currentHour = today.getHours();

      // 如果日期不是今天，直接返回false
      if (date !== currentDate) {
        return {
          status: 'success',
          isInSlots: false,
          message: '不在当前时间段内'
        };
      }

      // 定义时间段映射
      const timeSlotMap = {
        1: { start: 8, end: 10 },
        2: { start: 10, end: 12 },
        3: { start: 14, end: 16 },
        4: { start: 16, end: 18 }
      };

      // 检查当前时间是否在预约时间段内
      const isInSlots = timeSlots.some(slot => {
        const slotTime = timeSlotMap[slot];
        return currentHour >= slotTime.start && currentHour < slotTime.end;
      });

      return {
        status: 'success',
        isInSlots,
        message: isInSlots ? '在当前时间段内' : '不在当前时间段内'
      };
    } catch (error) {
      console.error('检查当前时间失败:', error);
      return {
        status: 'error',
        message: `检查当前时间失败: ${error.message}`
      };
    }
  },

  /**
   * 添加预约记录
   * 实现了多重容错机制：
   * 1. 参数格式自动修复
   * 2. 数据类型自动转换
   * 3. 必填字段验证
   * 
   * @param {Object} params 预约参数
   * @param {string} params.personName 预约人姓名
   * @param {string} params.personId 预约人ID
   * @param {string} params.sysName 实验室名称
   * @param {string} params.sysId 实验室ID
   * @param {string} params.sbName 设备名称
   * @param {string} params.sbId 设备ID
   * @param {string} params.date 预约日期
   * @param {Array<number>|string|number} params.timeSlots 预约时间段
   * @returns {Promise<Object>} 预约结果
   */
  async addReservation({ personName, personId, sysName, sysId, sbName, sbId, date, timeSlots }) {
    console.log('调用addReservation函数:', { personName, personId, sysName, sysId, sbName, sbId, date, timeSlots });

    try {
      // 参数验证
      if (!personName || !personId || !sysName || !sysId || !sbName || !sbId || !date || !timeSlots) {
        return {
          status: 'error',
          message: '缺少必要参数'
        };
      }

      // 时间段格式自动修复
      let formattedTimeSlots = timeSlots;
      if (!Array.isArray(timeSlots)) {
        console.warn('timeSlots格式错误，尝试修复:', timeSlots);
        if (typeof timeSlots === 'string') {
          try {
            formattedTimeSlots = JSON.parse(timeSlots);
          } catch (e) {
            const matches = timeSlots.match(/\[?([1-4])[,\d]*\]?/);
            if (matches && matches[1]) {
              formattedTimeSlots = [Number(matches[1])];
            } else {
              formattedTimeSlots = [];
            }
          }
        } else if (typeof timeSlots === 'number') {
          formattedTimeSlots = [timeSlots];
        }

        if (!Array.isArray(formattedTimeSlots)) {
          formattedTimeSlots = [];
        }
      } else {
        formattedTimeSlots = timeSlots.map(slot => {
          if (typeof slot === 'string') {
            return Number(slot);
          }
          return slot;
        });
      }

      // 验证时间段格式
      if (!formattedTimeSlots.length || !formattedTimeSlots.every(slot => slot >= 1 && slot <= 4)) {
        return {
          status: 'error',
          message: '时间段格式错误，必须是1-4的数字数组'
        };
      }

      // 检查当前时间是否在预约时间段内
      const currentTimeCheck = this.checkCurrentTimeInSlots(date, formattedTimeSlots);
      if (currentTimeCheck.isInSlots) {
        return {
          status: 'error',
          message: '当前时间段内不能进行预约'
        };
      }

      // 检查时间段是否已被预约
      const conflictCheck = await this.checkTimeConflict(date, formattedTimeSlots);
      if (conflictCheck.hasConflict) {
        return {
          status: 'error',
          message: '所选时间段已被预约'
        };
      }

      const data = {
        personName,
        personID: personId,
        stauts: '已预约',
        time: formattedTimeSlots,
        date,
        sysName,
        sysID: sysId,
        sbName,
        sbID: sbId
      };

      console.log('格式化后的预约数据:', data);
      const result = await add('yyjl', data);
      return {
        status: 'success',
        id: result.id,
        message: '预约成功'
      };
    } catch (error) {
      console.error('添加预约记录失败:', error);
      return {
        status: 'error',
        message: `预约失败: ${error.message}`
      };
    }
  },

  /**
   * 获取用户信息
   * 实现了多重容错机制：
   * 1. 先尝试从缓存获取
   * 2. 如果失败，尝试从其他存储位置获取
   * 3. 如果还是失败，返回错误信息
   * 
   * @returns {Promise<Object>} 用户信息
   */
  async getUserInfo() {
    console.log('调用getUserInfo函数');

    try {
      // 策略1：从缓存获取
      const userInfo = uni.getStorageSync('user');
      if (userInfo) {
        return {
          status: 'success',
          data: userInfo,
          message: '成功获取用户信息'
        };
      }

      // 策略2：尝试从其他存储位置获取
      const localUserInfo = uni.getStorageSync('localUser');
      if (localUserInfo) {
        return {
          status: 'success',
          data: localUserInfo,
          message: '成功获取本地用户信息'
        };
      }

      return {
        status: 'error',
        message: '未找到用户信息，请先登录'
      };
    } catch (error) {
      console.error('获取用户信息失败:', error);
      return {
        status: 'error',
        message: `获取用户信息失败: ${error.message}`
      };
    }
  },

  /**
   * 统计实验室和设备数量
   * 实现了多重容错机制：
   * 1. 先尝试精确统计
   * 2. 如果失败，尝试模糊统计
   * 3. 如果还是失败，返回错误信息
   * 
   * @returns {Promise<Object>} 统计结果
   */
  async getStatistics() {
    console.log('调用getStatistics函数');

    try {
      // 策略1：精确统计
      const labCount = await count('syslb', {});
      const equipmentCount = await count('sblb', {});

      // 策略2：如果统计失败，尝试模糊统计
      if (!labCount?.total || !equipmentCount?.total) {
        const labCountFallback = await count('syslb', { status: { $exists: true } });
        const equipmentCountFallback = await count('sblb', { status: { $exists: true } });

        return {
          status: 'success',
          data: {
            labCount: labCountFallback?.total || 0,
            equipmentCount: equipmentCountFallback?.total || 0
          },
          message: `统计完成：${labCountFallback?.total || 0}个实验室，${equipmentCountFallback?.total || 0}个设备`
        };
      }

      return {
        status: 'success',
        data: {
          labCount: labCount.total,
          equipmentCount: equipmentCount.total
        },
        message: `统计完成：${labCount.total}个实验室，${equipmentCount.total}个设备`
      };
    } catch (error) {
      console.error('统计失败:', error);
      return {
        status: 'error',
        message: `统计失败: ${error.message}`
      };
    }
  },

  /**
   * 预约流程函数
   * 实现了完整的预约流程，包括：
   * 1. 获取用户信息
   * 2. 获取当前日期
   * 3. 验证预约参数
   * 4. 添加预约记录
   * 
   * @param {Object} params 预约参数
   * @param {string} params.sysName 实验室名称
   * @param {string} params.sysId 实验室ID
   * @param {string} params.sbName 设备名称
   * @param {string} params.sbId 设备ID
   * @param {string} [params.date] 预约日期
   * @param {Array<number>} params.timeSlots 预约时间段
   * @returns {Promise<Object>} 预约结果
   */
  async reservationProcess({ sysName, sysId, sbName, sbId, date, timeSlots }) {
    console.log('调用reservationProcess函数:', { sysName, sysId, sbName, sbId, date, timeSlots });

    try {
      // 步骤1: 获取用户信息
      const userInfoResult = await this.getUserInfo();
      if (userInfoResult.status !== 'success') {
        return {
          status: 'error',
          message: '获取用户信息失败，请先登录'
        };
      }

      const userInfo = userInfoResult.data;
      const personName = userInfo.name || userInfo.username;
      const personId = userInfo._id;

      if (!personId) {
        return {
          status: 'error',
          message: '获取用户ID失败，请重新登录'
        };
      }

      // 步骤2: 如果没有提供日期，则获取当前日期
      let reservationDate = date;
      if (!reservationDate) {
        const dateResult = this.getTodayDate();
        if (dateResult.status !== 'success') {
          return {
            status: 'error',
            message: '获取当前日期失败，请指定日期'
          };
        }
        reservationDate = dateResult.data;
      }

      // 步骤3: 验证时间段格式
      let formattedTimeSlots = timeSlots;
      if (!Array.isArray(timeSlots)) {
        console.warn('timeSlots格式错误，尝试修复:', timeSlots);
        if (typeof timeSlots === 'string') {
          try {
            formattedTimeSlots = JSON.parse(timeSlots);
          } catch (e) {
            const matches = timeSlots.match(/\[?([1-4])[,\d]*\]?/);
            if (matches && matches[1]) {
              formattedTimeSlots = [Number(matches[1])];
            } else {
              formattedTimeSlots = [];
            }
          }
        } else if (typeof timeSlots === 'number') {
          formattedTimeSlots = [timeSlots];
        }

        if (!Array.isArray(formattedTimeSlots)) {
          formattedTimeSlots = [];
        }
      } else {
        formattedTimeSlots = timeSlots.map(slot => {
          if (typeof slot === 'string') {
            return Number(slot);
          }
          return slot;
        });
      }

      // 验证时间段格式
      if (!formattedTimeSlots.length || !formattedTimeSlots.every(slot => slot >= 1 && slot <= 4)) {
        return {
          status: 'error',
          message: '时间段格式错误，必须是1-4的数字数组'
        };
      }

      // 步骤4: 调用预约函数
      const reservationResult = await this.addReservation({
        personName,
        personId,
        sysName,
        sysId,
        sbName,
        sbId,
        date: reservationDate,
        timeSlots: formattedTimeSlots
      });

      return reservationResult;
    } catch (error) {
      console.error('预约流程失败:', error);
      return {
        status: 'error',
        message: `预约流程失败: ${error.message}`
      };
    }
  },

  /**
   * 取消预约
   * 实现了多重容错机制：
   * 1. 支持多种ID格式
   * 2. 自动清理无效字符
   * 3. 验证更新结果
   * 
   * @param {string|Object} params 预约ID或包含ID的对象
   * @returns {Promise<Object>} 取消结果
   */
  async cancelReservation(params) {
    console.log('调用cancelReservation函数:', params);

    try {
      let reservationId;

      // 策略1：直接使用字符串ID
      if (typeof params === 'string') {
        reservationId = params;
      } else {
        // 策略2：从对象中提取ID
        reservationId = params?.reservationId || params?.id || params?.id || params?.reservationreservationId;
      }

      // 清理ID中可能存在的无效字符
      if (reservationId && typeof reservationId === 'string') {
        reservationId = reservationId.replace(/[null\s,，]/g, '');
      }

      if (!reservationId) {
        return {
          status: 'error',
          message: '缺少预约ID，请提供正确的预约记录ID'
        };
      }

      // 获取预约记录
      const doc = await db.collection('yyjl').doc(reservationId).get();
      if (!doc.data) {
        return {
          status: 'error',
          message: '预约记录不存在'
        };
      }

      // 检查当前时间是否在预约时间段内
      const currentTimeCheck = this.checkCurrentTimeInSlots(doc.data.date, doc.data.time);
      if (currentTimeCheck.isInSlots) {
        return {
          status: 'error',
          message: '当前时间段内不能取消预约'
        };
      }

      // 更新预约状态
      const result = await db.collection('yyjl').doc(reservationId).update({
        stauts: '已取消'
      });

      if (result.updated === 1) {
        return {
          status: 'success',
          message: '取消预约成功'
        };
      } else {
        return {
          status: 'error',
          message: '取消预约失败，请重试'
        };
      }
    } catch (error) {
      console.error('取消预约失败:', error);
      return {
        status: 'error',
        message: `取消预约失败: ${error.message}`
      };
    }
  }
};

export { functionDefinitions };
export default functions; 